
#include "stdAfx.h"
#include "headers.h"

extern "C" unsigned long OS_GetTime(void);


////////////////////////////////////////////////////////////////////////////////
// Define menus here ///////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

INT16 _ALL_MENUS[2][10] = {	// _ALL_MENUS[x][y] => x: num menus, y: max array size
	// Main menu
	{
		TXT_HELLO_WORLD,		// Title, -1 for no title
		_HCENTER | _VCENTER,	// Alignment
		24,						// Item height, -1 for auto height
		3,						// Num items
		TXT_DEMO1,			// First item
		TXT_DEMO2,
		TXT_DEMO3
	},

	// Main menu 2
	{
		TXT_ASK_SOUND,
		_LEFT | _VCENTER,
		24,
		2,
		TXT_YES,
		TXT_NO,
	},
};

////////////////////////////////////////////////////////////////////////////////
// CTOR & DTOR /////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

CScene::CScene()
{
	m_script = NULL;
	//m_tileset = NULL;
	m_camera = NULL;

	// Actors
	m_actors = new CActor**[cConstants::ACTLIST_COUNT];
	m_actorMap = new INT32*[cConstants::ACTLIST_COUNT];
	m_numActors = new INT32[cConstants::ACTLIST_COUNT];
	for(INT8 i=0; i<cConstants::ACTLIST_COUNT; i++)
	{
		m_actors[i] = new CActor*[cConstants::ACTSLOT_COUNT];
		m_actorMap[i] = new INT32[cConstants::ACTSLOT_COUNT];
		m_numActors[i] = 0;
		for(INT32 j=0; j<cConstants::ACTSLOT_COUNT; j++)
		{
			m_actors[i][j] = NULL;
		}
	}

	// Stored actors
	m_storeActors = new CActor*[cConstants::STOSLOT_COUNT];
	for(INT8 i=0; i<cConstants::STOSLOT_COUNT; i++)
	{
		m_storeActors[i] = NULL;
	}
	
	// Scripts
	m_scripts = new CScript*[cConstants::SCRSLOT_COUNT];
	for(INT8 i=0; i<cConstants::SCRSLOT_COUNT; i++)
	{
		m_scripts[i] = NULL;
	}
}

CScene::~CScene()
{
	// Actors
	for(INT8 i=0; i<cConstants::ACTLIST_COUNT; i++)
	{
		for(INT32 j=0; j<cConstants::ACTSLOT_COUNT; j++)
		{
			SAFE_DEL(m_actors[i][j]);
		}
		SAFE_DEL_ARRAY(m_actors[i]);
		SAFE_DEL_ARRAY(m_actorMap[i]);
	}
	SAFE_DEL_ARRAY(m_actors);
	SAFE_DEL_ARRAY(m_actorMap);
	SAFE_DEL_ARRAY(m_numActors);

	// Stored actors
	for(INT8 i=0; i<cConstants::STOSLOT_COUNT; i++)
	{
		SAFE_DEL(m_storeActors[i]);
	}
	SAFE_DEL_ARRAY(m_storeActors);

	// Scripts
	for(INT8 i=0; i<cConstants::SCRSLOT_COUNT; i++)
	{
		SAFE_DEL(m_scripts[i]);
	}
	SAFE_DEL_ARRAY(m_scripts);
	m_script = NULL;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CScene::Update()
{
	// Update script
	INT32 i, j;
	
	// Main script is supposed to be at slot 0.
	// We will update sub scripts first, then main script
	// to make sure m_script is not null after updating scripts.
	for(i=cConstants::SCRSLOT_COUNT - 1; i>=0; i--)
	{
		m_script = m_scripts[i];
		if(m_script != NULL)
		{
			if(GAME_INSTANCE->HasScreenTouched() && m_script->m_labelID != cConstants::LBL_INVALID)
			{
				m_script->GotoLabel(m_script->m_labelID);
				m_script->m_labelID = cConstants::LBL_INVALID;
			}
		
			while(!m_script->IsEnded())
			{
				if(ExecuteCommand(m_script->GetCommand(), m_script->GetParams(), true, m_script->GetCrtCommandNumParams()))
				{
					m_script->Forward();
				}
				else
				{
					break;
				}
			}
		}
	}

	// Update actors
	INT32 numActors;
	for(i=0; i<cConstants::ACTLIST_COUNT; i++)
	{
		numActors = m_numActors[i];
		for(j=0; j<numActors; j++)
		{
			m_actors[i][m_actorMap[i][j]]->Update();
		}
	}
}

void CScene::Paint()
{
	// Tileset bg
	//bool drawTileset = (m_tileset != NULL && m_tileset->m_actState != CActor::ACTSTATE_INACTIVE);
	//if(drawTileset)
	//{
	//	m_tileset->m_tileManager->DrawBackgroundLayers();
	//}

	// Objects
	INT32 numObjects;
	for(INT8 i=0; i<cConstants::ACTLIST_COUNT; i++)
	{
		if(i == cConstants::ACTLIST_HUD) continue;
		numObjects = m_numActors[i];
		for(INT32 j=0; j<numObjects; j++)
		{
			m_actors[i][m_actorMap[i][j]]->Paint(m_camera != NULL);

		}
	}

	// Tileset fg
	//if(drawTileset)
	//{
	//	m_tileset->m_tileManager->DrawOverlayLayers();
	//}

	// Hud
	numObjects = m_numActors[cConstants::ACTLIST_HUD];
	for(UINT8 j=0; j<numObjects; j++)
	{
		m_actors[cConstants::ACTLIST_HUD][m_actorMap[cConstants::ACTLIST_HUD][j]]->Paint(false);
	}
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CScene::SetScript(UINT8 slot, CScript *script)
{
	EndScript(slot);
	m_scripts[slot] = script;
}

void CScene::SetScript(UINT8 slot, UINT32 resID)
{
	CScript *script = CScript::LoadScript(resID);
	SetScript(slot, script);
}

void CScene::EndScript(UINT8 slot)
{
	SAFE_DEL(m_scripts[slot]);
}

INT32 exec_cmd_params[MAX_CMD_PARAMS];
bool CScene::ExecuteCommand(UINT16 cmd, UINT8 numParams, ...)
{
	// Passed params
	UINT8 numPassedParams = numParams;
	va_list vl;
	va_start(vl, numParams);
	for(UINT8 i=0; i<numParams; i++)
	{
		exec_cmd_params[i] = va_arg(vl, INT32);
	}
	va_end(vl);

	// Default params
	UINT8 numCmdParams = CScript::GetCommandNumParams(cmd);
	while(numParams < numCmdParams)
	{
		exec_cmd_params[numParams] = CScript::GetDefaultParam(cmd, numParams);
		numParams++;
	}

	return ExecuteCommand(cmd, exec_cmd_params, false, numPassedParams);
}

bool CScene::ExecuteCommand(UINT16 cmd, INT32 *params, bool isScriptCommand, UINT8 numParams)
{
	// - Return true if the scene should proceed to next command
	// - Return false the the scene should wait for current command to be
	//   completely processed before moving to next command

	switch(cmd)
	{
	//////////////////////////////////////////////////////////////////
	// Navigation ////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////
	case cConstants::CMD_LABEL:
		return true;

	case cConstants::CMD_GOTO:
		m_script->GotoLabel(params[cConstants::CMDPARAM_GOTO_LABELID]);
		return true;
		
	case cConstants::CMD_ON_TAP_GOTO:
		m_script->m_labelID = params[cConstants::CMDPARAM_ON_TAP_GOTO_LABELID];
		return true;

	case cConstants::CMD_IF:
		//if(isScriptCommand) must always be
		{
			bool res = EvalCond(params, 0, numParams - 1);
			UINT16 nextCmd = m_script->GetNextCommand();
			while(nextCmd == cConstants::CMD_ANDIF || nextCmd == cConstants::CMD_ORIF)
			{
				m_script->Forward();
				params = m_script->GetParams();
				numParams = m_script->GetCrtCommandNumParams();
				if(nextCmd == cConstants::CMD_ANDIF)
				{
					res &= EvalCond(params, 0, numParams - 1);
				}
				else // if(nextCmd == cConstants::CMD_ORIF)
				{
					res |= EvalCond(params, 0, numParams - 1);
				}
				nextCmd = m_script->GetNextCommand();
			}
			if(!res)
			{
				m_script->GotoElse();
			}
		}
		return true;

	case cConstants::CMD_ANDIF:
		return true;

	case cConstants::CMD_ORIF:
		return true;

	case cConstants::CMD_ELSE:
		//if(isScriptCommand) must always be
		{
			m_script->GotoEndif();
		}
		return true;

	case cConstants::CMD_ENDIF:
		return true;

	//////////////////////////////////////////////////////////////////
	// Sprites ///////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////
	case cConstants::CMD_LOAD_SPRITE:
		GAME_INSTANCE->LoadSprite(params[cConstants::CMDPARAM_LOAD_SPRITE_RESID]);
		if(isScriptCommand)
		{
			m_script->Forward();
		}
		return false;

	case cConstants::CMD_FREE_SPRITE:
		GAME_INSTANCE->UnloadSprite(params[cConstants::CMDPARAM_FREE_SPRITE_SLOT]);
		return true;

	//////////////////////////////////////////////////////////////////
	// Sound /////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////
	case cConstants::CMD_LOAD_MUSIC:
		{
			GAME_INSTANCE->LoadMusic(params[cConstants::CMDPARAM_LOAD_MUSIC_RESID]);
			if(isScriptCommand)
			{
				m_script->Forward();
			}
			return false;
		}

	case cConstants::CMD_LOAD_SFX:
		{
			GAME_INSTANCE->LoadSFX(params[cConstants::CMDPARAM_LOAD_SFX_RESID]);
			if(isScriptCommand)
			{
				m_script->Forward();
			}
			return false;
		}

	case cConstants::CMD_PLAY_MUSIC:
		GAME_INSTANCE->PlayCurrentMusic(params[cConstants::CMDPARAM_PLAY_MUSIC_LOOP]);
		return true;

	case cConstants::CMD_PLAY_SFX:
		GAME_INSTANCE->PlaySFX(params[cConstants::CMDPARAM_PLAY_SFX_RESID]);
		return true;

	case cConstants::CMD_STOP_MUSIC:
		GAME_INSTANCE->StopCurrentMusic();
		return true;

	case cConstants::CMD_STOP_SFX:
		GAME_INSTANCE->StopAllSFX();
		return true;

	case cConstants::CMD_FREE_MUSIC:
		// TODO: GAME_INSTANCE->FreeMusic();
		return true;

	case cConstants::CMD_FREE_SFX:
		if(params[cConstants::CMDPARAM_FREE_SFX_RESID] == 65535)
		{
			GAME_INSTANCE->FreeAllSFX();
		}
		else
		{
			GAME_INSTANCE->FreeSFX(params[cConstants::CMDPARAM_FREE_SFX_RESID]);
		}
		return true;

	//////////////////////////////////////////////////////////////////
	// Text //////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////
	case cConstants::CMD_LOAD_TEXT:
		GAME_INSTANCE->LoadTextPack(params[cConstants::CMDPARAM_LOAD_TEXT_RESID]);
		if(isScriptCommand)
		{
			m_script->Forward();
		}			
		return false;

	case cConstants::CMD_FREE_TEXT:
		// TODO: GAME_INSTANCE->FreeTextPack(params[cConstants::CMDPARAM_FREE_TEXT_RESID]);
		return true;

	//////////////////////////////////////////////////////////////////
	// Scene /////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////
	case cConstants::CMD_WAIT:
		{
			m_script->m_waitTime += GAME_INSTANCE->m_frameDT;
			if(m_script->m_waitTime >= params[cConstants::CMDPARAM_WAIT_MILLIS] / 1000.0f)
			{
				m_script->m_waitTime = 0;
				return true;
			}
			return false;
		}

	case cConstants::CMD_WAIT_ACTORS:
		{
			INT8 list = GET_ACTOR_LIST(params[0]);
			INT32 id = GET_ACTOR_ID(params[0]);
			int i, j;
			CActor* actor;
			if(!IsValidActorID(list, id))
			{
				if(list < cConstants::ACTLIST_COUNT)
				{
					// Wait a list
					for(j=0; j<m_numActors[list]; j++)
					{
						actor = m_actors[list][m_actorMap[list][j]];
						if(!actor->IsActionFinished())
						{
							return false;
						}
					}
					return true;
				}
				else
				{
					// Wait all actors
					for(i=0; i<cConstants::ACTLIST_COUNT; i++)
					{
						for(j=0; j<m_numActors[i]; j++)
						{
							actor = m_actors[i][m_actorMap[i][j]];
							if(!actor->IsActionFinished())
							{
								return false;
							}
						}
					}
					return true;
				}
			}
			else
			{
				// Wait specified actors
				for(i=0; i<16; i++) // max 16 params
				{
					list = GET_ACTOR_LIST(params[i]);
					id = GET_ACTOR_ID(params[i]);
					if(!IsValidActorID(list, id))
					{
						return true;
					}
					actor = m_actors[list][id];
					if(actor != NULL && !actor->IsActionFinished())
					{
						return false;
					}
				}
				return true;
			}
		}		

	case cConstants::CMD_START_CLOCK:
#if defined(WIN32)
		m_script->m_clockStartTime = time(NULL);
#elif  defined(ANDROID_OS) || defined(BADA_OS)
		m_script->m_clockStartTime = OS_GetTime();
#elif defined(IPHONE)
		m_script->m_clockStartTime = cSystem::GetTime();
#endif
		break;

	case cConstants::CMD_WAIT_CLOCK:
		{
#if defined(WIN32)
			UINT16 elapsed = (UINT16)(time(NULL) - m_script->m_clockStartTime);
#elif defined(ANDROID_OS) || defined(BADA_OS)
			UINT16 elapsed = (UINT16)(OS_GetTime() - m_script->m_clockStartTime);
#elif defined(IPHONE)
			UINT16 elapsed = (UINT16)(cSystem::GetTime() - m_script->m_clockStartTime);
#endif
			if(elapsed >= params[cConstants::CMDPARAM_WAIT_CLOCK_SECS])
			{
				break;
			}
			else
			{
				return false;
			}
		}

	case cConstants::CMD_YIELD:
		if(isScriptCommand)
		{
			m_script->Forward();
		}
		return false;

	case cConstants::CMD_EXEC_SCRIPT:
		{
			bool selfReplace = (m_script == m_scripts[params[cConstants::CMDPARAM_EXEC_SCRIPT_SLOT]]);
			SetScript(params[cConstants::CMDPARAM_EXEC_SCRIPT_SLOT], CScript::LoadScript(params[cConstants::CMDPARAM_EXEC_SCRIPT_RESID]));
			return (selfReplace ? false : true);
		}
		
	case cConstants::CMD_STOP_SCRIPT:
		{
			bool selfStop = (m_script == m_scripts[params[cConstants::CMDPARAM_EXEC_SCRIPT_SLOT]]);
			EndScript(params[cConstants::CMDPARAM_EXEC_SCRIPT_SLOT]);
			return (selfStop ? false : true);
		}

	case cConstants::CMD_DO_EVENTS:
		return false;

	case cConstants::CMD_FREE_MEMORY:
		// Currently nothing to do
		if(isScriptCommand)
		{
			m_script->Forward();
		}	
		return false;

	//////////////////////////////////////////////////////////////////
	// Actors ////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////
	case cConstants::CMD_ACTIVATE_ACTOR:
		{
			INT8 list = GET_ACTOR_LIST(params[cConstants::CMDPARAM_ACTIVATE_ACTOR_ID]);
			INT32 id = GET_ACTOR_ID(params[cConstants::CMDPARAM_ACTIVATE_ACTOR_ID]);
			if(IsValidActorID(list, id))
			{
				m_actors[list][id]->Activate();
			}
			else if(list >= 0 && list <= cConstants::ACTLIST_COUNT)
			{
				// Activate all actors in a list
				for(INT32 i=0; i<cConstants::ACTSLOT_COUNT; i++)
				{
					if(m_actors[list][i] != NULL && m_actors[list][i]->m_actState != CActor::ACTSTATE_ACTIVE)
					{
						m_actors[list][i]->Activate();
					}
				}
			}
			else
			{
				for(INT8 i=0; i<cConstants::ACTLIST_COUNT; i++)
				{
					for(INT32 j=0; j<cConstants::ACTSLOT_COUNT; j++)
					{
						if(m_actors[i][j] != NULL && m_actors[i][j]->m_actState != CActor::ACTSTATE_ACTIVE)
						{
							m_actors[i][j]->Activate();
						}
					}
				}
			}
			return true;
		}

	case cConstants::CMD_DEACTIVATE_ACTOR:
		{
			INT8 list = GET_ACTOR_LIST(params[cConstants::CMDPARAM_ACTIVATE_ACTOR_ID]);
			INT32 id = GET_ACTOR_ID(params[cConstants::CMDPARAM_ACTIVATE_ACTOR_ID]);
			if(IsValidActorID(list, id))
			{
				m_actors[list][id]->Deactivate();
			}
			else if(list >= 0 && list <= cConstants::ACTLIST_COUNT)
			{
				// Deactivate all actors in a list
				for(INT32 i=0; i<cConstants::ACTSLOT_COUNT; i++)
				{
					if(m_actors[list][i] != NULL && m_actors[list][i]->m_actState != CActor::ACTSTATE_INACTIVE)
					{
						m_actors[list][i]->Deactivate();
					}
				}
			}
			else
			{
				for(INT8 i=0; i<cConstants::ACTLIST_COUNT; i++)
				{
					for(INT32 j=0; j<cConstants::ACTSLOT_COUNT; j++)
					{
						if(m_actors[i][j] != NULL && m_actors[i][j]->m_actState != CActor::ACTSTATE_INACTIVE)
						{
							m_actors[i][j]->Deactivate();
						}
					}
				}
			}
			return true;
		}

	case cConstants::CMD_SET_ACTOR_POS:
		m_actors[GET_ACTOR_LIST(params[cConstants::CMDPARAM_SET_ACTOR_POS_ID])][GET_ACTOR_ID(params[cConstants::CMDPARAM_SET_ACTOR_POS_ID])]->SetPos(
			params[cConstants::CMDPARAM_SET_ACTOR_POS_X],
			params[cConstants::CMDPARAM_SET_ACTOR_POS_Y]);
		break;

	case cConstants::CMD_SET_ACTOR_PARAM:
		m_actors[GET_ACTOR_LIST(params[cConstants::CMDPARAM_SET_ACTOR_PARAM_ID])][GET_ACTOR_ID(params[cConstants::CMDPARAM_SET_ACTOR_PARAM_ID])]->SetParam(
			params[cConstants::CMDPARAM_SET_ACTOR_PARAM_PARAM],
			params[cConstants::CMDPARAM_SET_ACTOR_PARAM_VALUE]);
		return true;

	case cConstants::CMD_SET_ACTOR_ANIM:
		{
			CActor* actor = m_actors[GET_ACTOR_LIST(params[cConstants::CMDPARAM_SET_ACTOR_ANIM_ID])][GET_ACTOR_ID(params[cConstants::CMDPARAM_SET_ACTOR_ANIM_ID])];
			actor->m_anim->SetAnim(
				params[cConstants::CMDPARAM_SET_ACTOR_ANIM_ANIM],
				params[cConstants::CMDPARAM_SET_ACTOR_ANIM_LOOP] != 0);
			//actor->m_anim->m_iTransform = (params[cConstants::CMDPARAM_SET_ACTOR_ANIM_TRANS]);
			break;
		}

	case cConstants::CMD_REMOVE_ACTOR:
		{
			RemoveActor(params[cConstants::CMDPARAM_REMOVE_ACTOR_ID]);
			return true;
		}
		
	case cConstants::CMD_STORE_ACTOR:
		{
			m_storeActors[params[cConstants::CMDPARAM_STORE_ACTOR_SLOT]] = GetActor(params[cConstants::CMDPARAM_STORE_ACTOR_ID]);
			return true;
		}
		
	case cConstants::CMD_RESTORE_ACTOR:
		{
			// Add a dummy actor to make sure mapping exists
			CActor *dummy = AddActor(params[cConstants::CMDPARAM_RESTORE_ACTOR_ID], 0, 1);
			
			CActor *actor = m_storeActors[params[cConstants::CMDPARAM_RESTORE_ACTOR_SLOT]];
			if(actor->m_actType == cConstants::ACTTYPE_MENU)
			{
#if MENU_BEHAVIOR_TOUCH_ONLY
				actor->m_menu->SelectItemIndex(-1);
#else
				actor->m_menu->SelectItemIndex(0);
#endif
			}
			
			m_actors[GET_ACTOR_LIST(params[cConstants::CMDPARAM_RESTORE_ACTOR_ID])][GET_ACTOR_ID(params[cConstants::CMDPARAM_RESTORE_ACTOR_ID])] = actor;
			SAFE_DEL(dummy);

			return true;
		}
		
	case cConstants::CMD_REMOVE_STORED_ACTOR:
		{
			if(params[cConstants::CMDPARAM_REMOVE_STORED_ACTOR_SLOT] == cConstants::ACTSLOT_INVALID)
			{
				// Free all
				for(int i=0; i<cConstants::STOSLOT_COUNT; i++)
				{
					SAFE_DEL(m_storeActors[i]);
				}
			}
			else
			{
				// Free 1 actor
				SAFE_DEL(m_storeActors[params[cConstants::CMDPARAM_REMOVE_STORED_ACTOR_SLOT]]);
			}
			return true;
		}

	case cConstants::CMD_ADD_ACTOR_FADE:
		{
			CActor* actor = AddActor(params[cConstants::CMDPARAM_ADD_ACTOR_FADE_ID], cConstants::ACTTYPE_FADE, cConstants::ACTPARAM_FADE_PARAM_COUNT);
			actor->SetPos(params[cConstants::CMDPARAM_ADD_ACTOR_FADE_X], params[cConstants::CMDPARAM_ADD_ACTOR_FADE_Y]);
			actor->SetParam(cConstants::ACTPARAM_FADE_TYPE,		params[cConstants::CMDPARAM_ADD_ACTOR_FADE_TYPE]);
			actor->SetParam(cConstants::ACTPARAM_FADE_DURATION,	params[cConstants::CMDPARAM_ADD_ACTOR_FADE_MILLIS]);
			actor->SetParam(cConstants::ACTPARAM_FADE_R,		params[cConstants::CMDPARAM_ADD_ACTOR_FADE_R]);
			actor->SetParam(cConstants::ACTPARAM_FADE_G,		params[cConstants::CMDPARAM_ADD_ACTOR_FADE_G]);
			actor->SetParam(cConstants::ACTPARAM_FADE_B,		params[cConstants::CMDPARAM_ADD_ACTOR_FADE_B]);
			actor->SetParam(cConstants::ACTPARAM_FADE_END,		params[cConstants::CMDPARAM_ADD_ACTOR_FADE_END]);
			actor->SetParam(cConstants::ACTPARAM_FADE_W,		params[cConstants::CMDPARAM_ADD_ACTOR_FADE_W]);
			actor->SetParam(cConstants::ACTPARAM_FADE_H,		params[cConstants::CMDPARAM_ADD_ACTOR_FADE_H]);
			return true;
		}

	//case cConstants::CMD_ADD_ACTOR_TILESET:
	//	{
	//		CActor* actor = AddActor(params[cConstants::CMDPARAM_ADD_ACTOR_TILESET_ID], cConstants::ACTTYPE_TILESET, cConstants::ACTPARAM_TILESET_PARAM_COUNT);
	//		actor->m_tileManager = new cTileManager();
	//		actor->m_tileManager->LoadTilemap(params[cConstants::CMDPARAM_ADD_ACTOR_TILESET_RESID]);
	//		actor->SetPos(params[cConstants::CMDPARAM_ADD_ACTOR_TILESET_X],	params[cConstants::CMDPARAM_ADD_ACTOR_TILESET_Y]);
	//		actor->SetParam(cConstants::ACTPARAM_TILESET_SPRITEID,			params[cConstants::CMDPARAM_ADD_ACTOR_TILESET_SPRITE]);
	//		actor->SetParam(cConstants::ACTPARAM_TILESET_PAL,				params[cConstants::CMDPARAM_ADD_ACTOR_TILESET_PAL]);
	//		return true;
	//	}

	case cConstants::CMD_ADD_ACTOR_MENU:
		{
			CActor* actor = AddActor(params[cConstants::CMDPARAM_ADD_ACTOR_MENU_ID], cConstants::ACTTYPE_MENU, cConstants::ACTPARAM_MENU_PARAM_COUNT);
			actor->SetPos(params[cConstants::CMDPARAM_ADD_ACTOR_MENU_X], params[cConstants::CMDPARAM_ADD_ACTOR_MENU_Y]);
			actor->m_menu = new CMenu(_ALL_MENUS[params[cConstants::CMDPARAM_ADD_ACTOR_MENU_RESID]]);
			actor->m_menu->SetFont(GAME_INSTANCE->GetSprite(params[cConstants::CMDPARAM_ADD_ACTOR_MENU_IFONT]), GAME_INSTANCE->GetSprite(params[cConstants::CMDPARAM_ADD_ACTOR_MENU_TFONT]));
			return true;
		}

	case cConstants::CMD_ADD_ACTOR_RECT:
	case cConstants::CMD_ADD_ACTOR_ANIM:
	case cConstants::CMD_ADD_ACTOR_TEXT:
	case cConstants::CMD_ADD_ACTOR_CAMERA:
		{
			UINT8 actorType = 0, numParams = 0;
			if(cmd == cConstants::CMD_ADD_ACTOR_RECT)
			{
				actorType = cConstants::ACTTYPE_RECT;
				numParams = cConstants::ACTPARAM_RECT_PARAM_COUNT;
			}
			else if(cmd == cConstants::CMD_ADD_ACTOR_ANIM)
			{
				actorType = cConstants::ACTTYPE_ANIM;
				numParams = cConstants::ACTPARAM_ANIM_PARAM_COUNT;
			}
			else if(cmd == cConstants::CMD_ADD_ACTOR_TEXT)
			{
				actorType = cConstants::ACTTYPE_TEXT;
				numParams = cConstants::ACTPARAM_TEXT_PARAM_COUNT;
			}
			else if(cmd == cConstants::CMD_ADD_ACTOR_CAMERA)
			{
				actorType = cConstants::ACTTYPE_CAMERA;
				numParams = cConstants::ACTPARAM_CAMERA_PARAM_COUNT;
			}
			CActor* actor = AddActor(params[0], actorType, numParams);
			actor->SetPos(params[1], params[2]);
			SetActorParams(params[0], numParams, params + 3); // + 3: 0 = id, 1 = posX, 2 = posY, 3... = params
			return true;
		}

	case cConstants::CMD_SET_ACTIVE_CAMERA:
		{
			//if(m_camera != NULL)
			//{
			//	// Only active camera has a tile-manager
			//	m_camera->m_tileManager = NULL;
			//}
			INT8 cameraList = GET_ACTOR_LIST(params[cConstants::CMDPARAM_SET_ACTIVE_CAMERA_ID]);
			INT32 cameraID = GET_ACTOR_ID(params[cConstants::CMDPARAM_SET_ACTIVE_CAMERA_ID]);
			if(IsValidActorID(cameraList, cameraID))
			{
				m_camera = m_actors[cameraList][cameraID];
			}
			else
			{
				m_camera = NULL;
			}

			if(m_camera != NULL)
			{
				if(m_camera->m_actState == CActor::ACTSTATE_INACTIVE)
				{
					m_camera->Activate();
				}
				//if(m_tileset != NULL)
				//{
				//	INT16 minX, minY, maxX, maxY;
				//	m_camera->m_tileManager = GetTileManager();
				//	m_camera->m_tileManager->GetMapScrollLimits(minX, minY, maxX, maxY);
				//	m_camera->SetCameraScrollingLimit(minX, minY, maxX, maxY);
				//}
			}
			return true;
		}

	//case cConstants::CMD_SET_ACTIVE_TILESET:
	//	{
	//		INT8 tilesetList = GET_ACTOR_LIST(params[cConstants::CMDPARAM_SET_ACTIVE_TILESET_ID]);
	//		INT32 tilesetID = GET_ACTOR_ID(params[cConstants::CMDPARAM_SET_ACTIVE_TILESET_ID]);
	//		if(IsValidActorID(tilesetList, tilesetID))
	//		{
	//			m_tileset = m_actors[tilesetList][tilesetID];
	//		}
	//		else
	//		{
	//			m_tileset = NULL;
	//		}
	//			
	//		if(m_tileset != NULL)
	//		{
	//			if(m_tileset->m_actState == CActor::ACTSTATE_INACTIVE)
	//			{
	//				m_tileset->Activate();
	//			}
	//			if(m_camera != NULL)
	//			{
	//				INT16 minX, minY, maxX, maxY;
	//				m_camera->m_tileManager = GetTileManager();
	//				m_camera->m_tileManager->GetMapScrollLimits(minX, minY, maxX, maxY);
	//				m_camera->SetCameraScrollingLimit(minX, minY, maxX, maxY);
	//			}
	//		}
	//		return true;
	//	}

	case cConstants::CMD_ACTOR_MOVE:
		{
			m_actors[GET_ACTOR_LIST(params[cConstants::CMDPARAM_ACTOR_MOVE_ID])][GET_ACTOR_ID(params[cConstants::CMDPARAM_ACTOR_MOVE_ID])]->Move(
				params[cConstants::CMDPARAM_ACTOR_MOVE_DIR],
				params[cConstants::CMDPARAM_ACTOR_MOVE_TYPE],
				params[cConstants::CMDPARAM_ACTOR_MOVE_DEST],
				params[cConstants::CMDPARAM_ACTOR_MOVE_P1],
				params[cConstants::CMDPARAM_ACTOR_MOVE_P2],
				params[cConstants::CMDPARAM_ACTOR_MOVE_P3],
				params[cConstants::CMDPARAM_ACTOR_MOVE_P4]);
			return true;
		}

	case cConstants::CMD_ACTOR_BLINK:
		m_actors[GET_ACTOR_LIST(params[cConstants::CMDPARAM_ACTOR_BLINK_ID])][GET_ACTOR_ID(params[cConstants::CMDPARAM_ACTOR_BLINK_ID])]->Blink(
			params[cConstants::CMDPARAM_ACTOR_BLINK_MILLIS],
			params[cConstants::CMDPARAM_ACTOR_BLINK_DUR]);
		return true;

	case cConstants::CMD_ACTOR_SHAKE:
		m_actors[GET_ACTOR_LIST(params[cConstants::CMDPARAM_ACTOR_SHAKE_ID])][GET_ACTOR_ID(params[cConstants::CMDPARAM_ACTOR_SHAKE_ID])]->Shake(
			params[cConstants::CMDPARAM_ACTOR_SHAKE_TYPE],
			params[cConstants::CMDPARAM_ACTOR_SHAKE_RX],
			params[cConstants::CMDPARAM_ACTOR_SHAKE_RY],
			params[cConstants::CMDPARAM_ACTOR_SHAKE_MILLIS]);
		return true;

	//////////////////////////////////////////////////////////////////
	// Variables /////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////
	case cConstants::CMD_SET_VAR:
		CScript::SetVar(params[cConstants::CMDPARAM_SET_VAR_ID], EvalExp(params, 1, numParams - 1));
		return true;
	}

	return true;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

CActor* CScene::AddActor(INT32 actID, UINT8 type, UINT8 numParams)
{
	INT8 list = GET_ACTOR_LIST(actID);
	INT32 id = GET_ACTOR_ID(actID);

	SAFE_DEL(m_actors[list][id]);
	m_actors[list][id] = new CActor(this, type, numParams);

	for(UINT8 i=0; i<m_numActors[list]; i++)
	{
		if(m_actorMap[list][i] == id)
		{
			// Mapping exists
			return m_actors[list][id];
		}
		if(m_actorMap[list][i] > id)
		{
			// Insert at i
			for(UINT8 j=m_numActors[list]; j>i; j--)
			{
				m_actorMap[list][j] = m_actorMap[list][j - 1];
			}
			m_actorMap[list][i] = id;
			m_numActors[list]++;
			return m_actors[list][id];
		}
	}
	m_actorMap[list][m_numActors[list]++] = id;

	return m_actors[list][id];
}

void CScene::RemoveActor(INT32 id)
{
	RemoveActor(GET_ACTOR_LIST(id), GET_ACTOR_ID(id));
}

void CScene::RemoveActor(INT8 list, INT32 id)
{
	if(IsValidActorID(list, id))
	{
		// Remove 1 actor
		for(UINT8 i=0; i<m_numActors[list]; i++)
		{
			if(m_actorMap[list][i] == id)
			{
				m_numActors[list]--;
				for(UINT8 j=i; j<m_numActors[list]; j++)
				{
					m_actorMap[list][j] = m_actorMap[list][j + 1];
				}
				break;
			}
		}
		if(m_actors[list][id] == m_camera)
		{
			m_camera = NULL;
		}
		//if(m_actors[list][id] == m_tileset)
		//{
		//	m_tileset = NULL;
		//}
		// [Sinh.2010/06/09] only delete if actor is not stored
		for(INT8 i=0; i<cConstants::STOSLOT_COUNT; i++)
		{
			if(m_storeActors[i] == m_actors[list][id])
			{
				SAFE_DEL(m_actors[list][id]);
				break;
			}
		}
	}
	else if(list >= 0 && list < cConstants::ACTLIST_COUNT)
	{
		// Remove 1 list
		for(INT32 i=0; i<cConstants::ACTSLOT_COUNT; i++)
		{
			RemoveActor(list, i);
		}
	}
	else
	{
		// Remove all
		for(INT8 i=0; i<cConstants::ACTLIST_COUNT; i++)
		{
			for(INT32 j=0; j<cConstants::ACTSLOT_COUNT; j++)
			{
				RemoveActor(i, j);
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CScene::SetActorParams(INT32 id, UINT8 numParams, INT32* params)
{
	CActor* actor = m_actors[GET_ACTOR_LIST(id)][GET_ACTOR_ID(id)];
	for(UINT8 i=0; i<numParams; i++)
	{
		actor->SetParam(i, params[i]);
	}
}

bool CScene::IsValidActorID(INT8 actList, INT32 actID)
{
	return (actList >= 0 && actList < cConstants::ACTLIST_COUNT && actID >= 0 && actID < cConstants::ACTSLOT_COUNT);
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

INT32 CScene::EvalExp(INT32 *params, UINT8 start, UINT8 end, UINT8 *weight)
{
	if(start == end)
	{
		return params[start];
	}

	bool delete_weight = false;
	INT32 res = 0;

	if(weight == NULL)
	{
		INT16 op;
#ifdef _DEBUG
		_DBG("EvalExp: ");
		for(UINT8 i=start; i<=end; i++)
		{
			op = (INT16)params[i];
			if(op == OP_ADD) _DBG("+ ");
			else if(op == OP_SUB) _DBG("- ");
			else if(op == OP_MUL) _DBG("* ");
			else if(op == OP_DIV) _DBG("/ ");
			else if(op == OP_LBR) _DBG("( ");
			else if(op == OP_RBR) _DBG(") ");
			else _DBG("%d ", op);
		}
#endif
		// Set weight of each operator
		// Smaller weight = less priority
		UINT8 len = end + 1;
		UINT8 brw = 0;
		weight = new UINT8[len];
		memset(weight, 255, len * sizeof(UINT8));
		delete_weight = true;
		for(UINT8 i=start; i<len; i++)
		{
			op = (INT16)params[i];
			if(op == OP_ADD || op == OP_SUB)
			{
				weight[i] = brw;
			}
			else if(op == OP_MUL || op == OP_DIV)
			{
				weight[i] = brw + 1;
			}
			else if(op == OP_LBR)
			{
				brw += 2;
			}
			else if(op == OP_RBR)
			{
				brw -= 2;
			}
		}
	}

	// Find the left-most smallest weight
	// Also find position of a number
	UINT8 smallest_weight = 254; // 255 => 254 to avoid duplicating with numbers, brackets...
	UINT8 left = 255;
	UINT8 numPos = 255;
	for(UINT8 i=start; i<=end; i++)
	{
		if(weight[i] <= smallest_weight)
		{
			smallest_weight = weight[i];
			left = i;
		}
		else if(weight[i] == 255 && ((INT16)params[i]) != OP_LBR && ((INT16)params[i]) != OP_RBR)
		{
			numPos = i;
		}
	}

	if(smallest_weight == 254)
	{
		// All elements have the same weight 255
		// => contains only numbers or brackets
		// => find numbers
		res = params[numPos];
	}
	else
	{
		// Evaluation
		INT32 resL = EvalExp(params, start, left - 1, weight);
		INT32 resR = EvalExp(params, left + 1, end, weight);
		INT16 op = (INT16)params[left];
		if(op == OP_ADD) res = resL + resR;
		if(op == OP_SUB) res = resL - resR;
		if(op == OP_MUL) res = resL * resR;
		if(op == OP_DIV) res = resL / resR;
	}

	if(delete_weight)
	{
#ifdef _DEBUG
		_DBG("= %d\n", res);
#endif
		SAFE_DEL_ARRAY(weight);
	}

	return res;
}

bool CScene::EvalCond(INT32 *params, UINT8 start, UINT8 end)
{
	// Find position of condition operator
	UINT8 condPos = 255;
	INT16 op;
	for(UINT8 i=start; i<=end; i++)
	{
		op = (INT16)params[i];
		if(op == OP_LAR || op == OP_LEQ || op == OP_SMA || op == OP_SEQ || op == OP_EQU || op == OP_NEQ)
		{
			condPos = i;
			break;
		}
	}

	if(condPos == 255)
	{
		_DBG("EvalCond: invalid condition\n"); 
		return false;
	}

	bool res = false;
	INT32 lhs = EvalExp(params, start, condPos - 1);
	INT32 rhs = EvalExp(params, condPos + 1, end);
	if(op == OP_LAR) res = (lhs > rhs);
	if(op == OP_LEQ) res = (lhs >= rhs);
	if(op == OP_SMA) res = (lhs < rhs);
	if(op == OP_SEQ) res = (lhs <= rhs);
	if(op == OP_EQU) res = (lhs == rhs);
	if(op == OP_NEQ) res = (lhs != rhs);

#ifdef _DEBUG
	_DBG("EvalCond: ");
	for(UINT8 i=start; i<=end; i++)
	{
		op = (INT16)params[i];
		if(op == OP_ADD) _DBG("+ ");
		else if(op == OP_SUB) _DBG("- ");
		else if(op == OP_MUL) _DBG("* ");
		else if(op == OP_DIV) _DBG("/ ");
		else if(op == OP_LBR) _DBG("( ");
		else if(op == OP_RBR) _DBG(") ");
		else if(op == OP_LAR) _DBG("> ");
		else if(op == OP_LEQ) _DBG(">= ");
		else if(op == OP_SMA) _DBG("< ");
		else if(op == OP_SEQ) _DBG("<= ");
		else if(op == OP_EQU) _DBG("== ");
		else _DBG("%d ", op);
	}
	_DBG("= %d\n", res);
#endif

	return res;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


